﻿using System;
using System.Diagnostics;
using System.IO;
using EnvDTE;

namespace SolutionSettings {
    internal class SettingsManager {
        private readonly IFileSystem FS;
        private readonly ISettingsProvider SP;

        public SettingsManager(IFileSystem fs, ISettingsProvider sp) {
            FS = fs;
            SP = sp;
        }

        public Solution ActiveSolution {
            get;
            private set;
        }

        public string ActiveSettingsSource {
            get;
            private set;
        }

        public void SolutionOpened(Solution solution) {
            if (ActiveSolution != null) {
                throw new InvalidOperationException("Previous solution was not closed.");
            }
            ActiveSolution = solution;

            var slnFile = ActiveSolution.FileName;
            var settingsFile = Path.ChangeExtension(slnFile, ".settings");

            Trace.TraceInformation("Solution {0} opened", slnFile);
            Trace.TraceInformation("File {0} exists == {1}", settingsFile, FS.FileExists(settingsFile));

            if (!FS.FileExists(settingsFile)) {
                // No settings to load
                return;
            }

            // Check if current settings are for this solution
            if (String.Equals(ActiveSettingsSource, settingsFile, StringComparison.OrdinalIgnoreCase)) {
                // These settings are already active.
                return;
            }

            if (String.IsNullOrEmpty(ActiveSettingsSource)) {
                // TODO: Save current settings as revert
            } else {
                // TODO: Save current settings to active source

                // TODO: Revert settings
            }

            // Import settings from settingsFile
            var settings = SP.Read(FS, settingsFile);
            Apply(settings);

            // Store persistent marker for which settings we are using.
            ActiveSettingsSource = settingsFile;
        }

        internal void Apply(ISettingsFile settings) {
            // TODO: Apply settings to VS
        }

        public void SolutionRenamed(string oldName) {
            if (ActiveSolution == null) {
                throw new InvalidOperationException("No solution is open.");
            }
            if (string.IsNullOrEmpty(oldName)) {
                throw new ArgumentNullException("oldName");
            }

            var slnFile = ActiveSolution.FileName;
            var oldPath = Path.Combine(Path.GetDirectoryName(slnFile), oldName + ".settings");
            var newPath = Path.ChangeExtension(slnFile, ".settings");

            Trace.TraceInformation("Renaming from {0} to {1}", oldPath, newPath);

            if (!FS.FileExists(oldPath)) {
                // No settings to change
                Trace.TraceInformation("File {0} does not exist.", oldPath);
                return;
            }

            try {
                FS.MoveFile(oldPath, newPath);
                Trace.TraceInformation("Solution renamed from {0} to {1}. Renaming associated settings file {2}.", oldName, slnFile, oldPath);

                // Update persistent marker
                ActiveSettingsSource = newPath;
            } catch (FileNotFoundException) {
                Trace.TraceWarning("File {0} disappeared.", oldPath);
            } catch (IOException ex) {
                Trace.TraceError("Unable to rename settings file {0}.\n\n{1}", newPath, ex);
            } catch (Exception ex) {
                Trace.TraceError("Unexpected {0} while renaming settings file {1}\n\n{2}", ex.GetType().FullName, oldPath, ex.ToString());
            }

            // Rename the revert file
            oldPath += ".revert";
            newPath += ".revert";

            if (!FS.FileExists(oldPath)) {
                // No settings to change
                Trace.TraceInformation("File {0} does not exist.", oldPath);
                return;
            }

            try {
                FS.MoveFile(oldPath, newPath);
                Trace.TraceInformation("Solution renamed from {0} to {1}. Renaming associated settings file {2}.", oldName, slnFile, oldPath);
            } catch (FileNotFoundException) {
                Trace.TraceWarning("File {0} disappeared.", oldPath);
            } catch (IOException ex) {
                Trace.TraceError("Unable to rename settings file {0}.\n\n{1}", newPath, ex);
            } catch (Exception ex) {
                Trace.TraceError("Unexpected {0} while renaming settings file {1}\n\n{2}", ex.GetType().FullName, oldPath, ex.ToString());
            }
        }

        public bool CanSolutionClose() {
            if (ActiveSolution == null) {
                throw new InvalidOperationException("No solution is open.");
            }

            // TODO: Offer to update saved settings file
            return true;
        }

        public void SolutionClosed() {
            ActiveSolution = null;

            // TODO: Apply benchmark settings

            // TODO: Remove persistent marker (see SolutionEvents_Opened)
        }
    }
}
